package game.controller;

import game.controller.Region.LandRegion;
import game.controller.Region.Region;
import game.controller.Region.Port;
import game.controller.Unit.*;
import game.util.GameMsg;
import game.util.GameLogger;
import shared.controller.LobbyConstants;
import lobby.controller.Nation;
import lobby.controller.User;

import java.util.ArrayList;

/**
 * NationInstance.java  Date Created: Nov 7, 2012
 *
 * Purpose: To keep track of everything related to a Nation in game.
 *
 * Description:
 *
 * @author Chrisb
 */
public class NationInstance {

    public NationInstance(int nation, int startingPap, int startingScene, MapInstance map) {
        this.nation = nation;
        this.map = map;
        scenario = startingScene;
        PAPs = startingPap;
        productionPoints = 0;
        playerNation = false;
        politicalStatus = new int[7];
        for (int i = 0; i < politicalStatus.length; i++)
            if (i == this.nation - 1)
                politicalStatus[i] = THIS_NATION;
            else
                politicalStatus[i] = NEUTRAL;
        isCapitalCaptured = false;
        hasCapitalBeenCaptured = false;
        isCapitalAnnexed = false;

        initNation();
    }

    private void initNation() {
        military = new ArrayList<MilitaryUnit>();
        territory = new ArrayList<LandRegion>();
        territory.addAll(getHomelands());
        switch(nation) {
            case Nation.FRANCE:
                switch (scenario) {
                    case LobbyConstants.I: break;
                    case LobbyConstants.II: break;
                    case LobbyConstants.III: break;
                    case LobbyConstants.IV: break;
                    case LobbyConstants.V: break;
                    case LobbyConstants.V_V: break;
                    case LobbyConstants.VI: break;
                    case LobbyConstants.VII: break;
                    case LobbyConstants.VIII: break;
                    case LobbyConstants.IX: break;
                    case LobbyConstants.X:
                        //12 Inf || 1 E. Inf
                        //3  Cav || 1 H. Cav
                        //2  Art || 1 Gen || 3 Nav
                        for (int i = 0; i < 12; i++)
                            military.add(new Infantry(nation));
                        military.add(new EliteInfantry(nation));
                        for (int i = 0; i < 3; i++)
                            military.add(new Cavalry(nation));
                        military.add(new HeavyCavalry(nation));
                        for (int i = 0; i < 2; i++)
                            military.add(new Artillery(nation));
                        military.add(new General(nation));
                        for (int i = 0; i < 3; i++)
                            military.add(new NavalSquadron(nation));
                        //French Homelands only
//                        for (LandRegion r : map.getFrenchHomelands())
//                            territory.add(r);
                        break;
                }
                break;
            case Nation.GREAT_BRITAIN:
                switch (scenario) {
                    case LobbyConstants.I: break;
                    case LobbyConstants.II: break;
                    case LobbyConstants.III: break;
                    case LobbyConstants.IV: break;
                    case LobbyConstants.V: break;
                    case LobbyConstants.V_V: break;
                    case LobbyConstants.VI: break;
                    case LobbyConstants.VII: break;
                    case LobbyConstants.VIII: break;
                    case LobbyConstants.IX: break;
                    case LobbyConstants.X:
                        //6 Inf || 1 E. Inf
                        //1 Cav || 1 H. Cav
                        //1 Art || 1 Gen || 6 Nav
                        for (int i = 0; i < 6; i++)
                            military.add(new Infantry(nation));
                        military.add(new EliteInfantry(nation));
                        military.add(new Cavalry(nation));
                        military.add(new HeavyCavalry(nation));
                        military.add(new Artillery(nation));
                        military.add(new General(nation));
                        military.add(new Admiral(nation));
                        for (int i = 0; i < 6; i++)
                            military.add(new NavalSquadron(nation));
                        //Great Britain Starting Land
//                        for (LandRegion r : map.getBritishHomelands())
//                            territory.add(r);
                        territory.add(map.getLandRegion(GameMsg.getString("Gibraltar")));
                        territory.add(map.getLandRegion(GameMsg.getString("Hanover")));
                        map.getLandRegion(GameMsg.getString("Gibraltar")).setControllingNation(nation);
                        map.getLandRegion(GameMsg.getString("Hanover")).setControllingNation(nation);
                        break;
                }
                break;
            case Nation.PRUSSIA:
                switch (scenario) {
                    case LobbyConstants.I: break;
                    case LobbyConstants.II: break;
                    case LobbyConstants.III: break;
                    case LobbyConstants.IV: break;
                    case LobbyConstants.V: break;
                    case LobbyConstants.V_V: break;
                    case LobbyConstants.VI: break;
                    case LobbyConstants.VII: break;
                    case LobbyConstants.VIII: break;
                    case LobbyConstants.IX: break;
                    case LobbyConstants.X:
                        //9 Inf || 1 E. Inf
                        //2 Cav || 1 H. Cav
                        //2 Art || 1 Gen
                        for (int i = 0; i < 9; i++)
                            military.add(new Infantry(nation));
                        military.add(new EliteInfantry(nation));
                        for (int i = 0; i < 2; i++)
                            military.add(new Cavalry(nation));
                        military.add(new HeavyCavalry(nation));
                        for (int i = 0; i < 2; i++)
                            military.add(new Artillery(nation));
                        military.add(new General(nation));
                        //Prussian Starting Land
//                        for (LandRegion r : map.getPrussianHomelands())
//                            territory.add(r);
                        territory.add(map.getLandRegion(GameMsg.getString("Westphalia")));
                        territory.add(map.getLandRegion(GameMsg.getString("HesseBerg")));
                        territory.add(map.getLandRegion(GameMsg.getString("Saxony")));
                        map.getLandRegion(GameMsg.getString("Westphalia")).setControllingNation(nation);
                        map.getLandRegion(GameMsg.getString("HesseBerg")).setControllingNation(nation);
                        map.getLandRegion(GameMsg.getString("Saxony")).setControllingNation(nation);
                        break;
                }
                break;
            case Nation.RUSSIA:
                switch (scenario) {
                    case LobbyConstants.I: break;
                    case LobbyConstants.II: break;
                    case LobbyConstants.III: break;
                    case LobbyConstants.IV: break;
                    case LobbyConstants.V: break;
                    case LobbyConstants.V_V: break;
                    case LobbyConstants.VI: break;
                    case LobbyConstants.VII: break;
                    case LobbyConstants.VIII: break;
                    case LobbyConstants.IX: break;
                    case LobbyConstants.X:
                        //12 Inf || 1 E. Inf
                        //2  Cav || 1 H. Cav
                        //2  Art || 2 Nav
                        for (int i = 0; i < 12; i++)
                            military.add(new Infantry(nation));
                        military.add(new EliteInfantry(nation));
                        for (int i = 0; i < 2; i++)
                            military.add(new Cavalry(nation));
                        military.add(new HeavyCavalry(nation));
                        for (int i = 0; i < 2; i++)
                            military.add(new Artillery(nation));
                        for (int i = 0; i < 2; i++)
                            military.add(new NavalSquadron(nation));
                        //Russian Starting Lands
//                        for (LandRegion r : map.getRussianHomelands())
//                            territory.add(r);
                        territory.add(map.getLandRegion(GameMsg.getString("Finland")));
                        territory.add(map.getLandRegion(GameMsg.getString("GrandDuchyWarsaw")));
                        territory.add(map.getLandRegion(GameMsg.getString("Moldavia")));
                        map.getLandRegion(GameMsg.getString("Finland")).setControllingNation(nation);
                        map.getLandRegion(GameMsg.getString("GrandDuchyWarsaw")).setControllingNation(nation);
                        map.getLandRegion(GameMsg.getString("Moldavia")).setControllingNation(nation);
                        break;
                }
                break;
            case Nation.OTTOMANS:
                switch (scenario) {
                    case LobbyConstants.I: break;
                    case LobbyConstants.II: break;
                    case LobbyConstants.III: break;
                    case LobbyConstants.IV: break;
                    case LobbyConstants.V: break;
                    case LobbyConstants.V_V: break;
                    case LobbyConstants.VI: break;
                    case LobbyConstants.VII: break;
                    case LobbyConstants.VIII: break;
                    case LobbyConstants.IX: break;
                    case LobbyConstants.X:
                        //8 Mil || 4 I. Cav
                        //1 Art || 2 Nav
                        for (int i = 0; i < 8; i++)
                            military.add(new Militia(nation));
                        for (int i = 0; i < 4; i++)
                        military.add(new IrregularCavalry(nation));
                        military.add(new Artillery(nation));
                        for (int i = 0; i < 2; i++)
                            military.add(new NavalSquadron(nation));
                        //Ottoman Starting Land
//                        for (LandRegion r : map.getOttomanHomelands())
//                            territory.add(r);
                        territory.add(map.getLandRegion(GameMsg.getString("Egypt")));
                        territory.add(map.getLandRegion(GameMsg.getString("Wallachia")));
                        territory.add(map.getLandRegion(GameMsg.getString("Bulgaria")));
                        territory.add(map.getLandRegion(GameMsg.getString("Serbia")));
                        territory.add(map.getLandRegion(GameMsg.getString("Bosnia")));
                        territory.add(map.getLandRegion(GameMsg.getString("Albania")));
                        territory.add(map.getLandRegion(GameMsg.getString("Macedonia")));
                        territory.add(map.getLandRegion(GameMsg.getString("Greece")));

                        map.getLandRegion(GameMsg.getString("Egypt")).setControllingNation(nation);
                        map.getLandRegion(GameMsg.getString("Wallachia")).setControllingNation(nation);
                        map.getLandRegion(GameMsg.getString("Bulgaria")).setControllingNation(nation);
                        map.getLandRegion(GameMsg.getString("Serbia")).setControllingNation(nation);
                        map.getLandRegion(GameMsg.getString("Bosnia")).setControllingNation(nation);
                        map.getLandRegion(GameMsg.getString("Albania")).setControllingNation(nation);
                        map.getLandRegion(GameMsg.getString("Macedonia")).setControllingNation(nation);
                        map.getLandRegion(GameMsg.getString("Greece")).setControllingNation(nation);
                        break;
                }
                break;
            case Nation.AUSTRIA_HUNGRY:
                switch (scenario) {
                    case LobbyConstants.I: break;
                    case LobbyConstants.II: break;
                    case LobbyConstants.III: break;
                    case LobbyConstants.IV: break;
                    case LobbyConstants.V: break;
                    case LobbyConstants.V_V: break;
                    case LobbyConstants.VI: break;
                    case LobbyConstants.VII: break;
                    case LobbyConstants.VIII: break;
                    case LobbyConstants.IX: break;
                    case LobbyConstants.X:
                        //12 Inf || 1 E. Inf
                        //3  Cav || 1 H. Cav
                        //2  Art || 1 Gen || 1 Nav
                        for (int i = 0; i < 12; i++)
                            military.add(new Infantry(nation));
                        military.add(new EliteInfantry(nation));
                        for (int i = 0; i < 3; i++)
                            military.add(new Cavalry(nation));
                        military.add(new HeavyCavalry(nation));
                        for (int i = 0; i < 2; i++)
                            military.add(new Artillery(nation));
                        military.add(new General(nation));
                        for (int i = 0; i < 1; i++)
                            military.add(new NavalSquadron(nation));
                        //Austria-Hungary Starting Lands
//                        for (LandRegion r : map.getAustrianHomelands())
//                            territory.add(r);
                        territory.add(map.getLandRegion(GameMsg.getString("Milan")));
                        territory.add(map.getLandRegion(GameMsg.getString("Venice")));
                        territory.add(map.getLandRegion(GameMsg.getString("Tuscany")));
                        map.getLandRegion(GameMsg.getString("Milan")).setControllingNation(nation);
                        map.getLandRegion(GameMsg.getString("Venice")).setControllingNation(nation);
                        map.getLandRegion(GameMsg.getString("Tuscany")).setControllingNation(nation);
                        break;
                }
                break;
            case Nation.SPAIN:
                switch (scenario) {
                    case LobbyConstants.I: break;
                    case LobbyConstants.II: break;
                    case LobbyConstants.III: break;
                    case LobbyConstants.IV: break;
                    case LobbyConstants.V: break;
                    case LobbyConstants.V_V: break;
                    case LobbyConstants.VI: break;
                    case LobbyConstants.VII: break;
                    case LobbyConstants.VIII: break;
                    case LobbyConstants.IX: break;
                    case LobbyConstants.X:
                        //7 Inf || 1 Cav
                        //1 Art || 2 Nav
                        for (int i = 0; i < 7; i++)
                            military.add(new Infantry(nation));
                        military.add(new Cavalry(nation));
                        military.add(new Artillery(nation));
                        for (int i = 0; i < 2; i++)
                            military.add(new NavalSquadron(nation));
                        //Spanish Starting
//                        for (LandRegion r : map.getSpanishHomelands())
//                            territory.add(r);
                        territory.add(map.getLandRegion(GameMsg.getString("Sicily")));
                        map.getLandRegion(GameMsg.getString("Sicily")).setControllingNation(nation);

                        //Neutral Minor Navies todo
                        //Swe - 1 || Den - 0 || Por - 1 || Hol - 1

                        break;
                }
                break;

        }
    }

    public boolean isAtWar() {
        for (int i : politicalStatus)
            if (i == WAR)
                return true;

        return false;
    }

    public int getProductionValue() {
        int value = 0;
        for (LandRegion r : territory)
            value += r.getProductionValue();
        return value;
    }

    //TODO move to CapitalRegion?? Yes
    public void annexCapital() { isCapitalAnnexed = true; isCapitalCaptured = false; }
    public void liberateCapital() { isCapitalCaptured = false; isCapitalAnnexed = false; }
    public void capitalCaptured() { isCapitalCaptured = true; hasCapitalBeenCaptured = true; isCapitalAnnexed = false; }
    public boolean hasCapitalBeenCaptured() { return hasCapitalBeenCaptured; }
    public boolean isCapitalCaptured() { return isCapitalCaptured; }
    public boolean isCapitalAnnexed() { return isCapitalAnnexed; }

    //TODO sueForPeace()

    public void makeNeutral(int nation) { politicalStatus[nation - 1] = NEUTRAL; }
    public void startAlliance(int nation) { politicalStatus[nation - 1] = ALLIED; }
    public void declareWar(int nation) { politicalStatus[nation - 1] = WAR; }
//    public void grantRightOfPassage(int nation) { politicalStatus[nation - 1] = PASSAGE_RIGHTS; }  //do i need these?? todo
//    public void grantGraceRights(int nation) { politicalStatus[nation - 1] = GRACE_RIGHTS; }  //do i need these?? todo
    public void receiveRightOfPassage(int nation) { politicalStatus[nation - 1] = HAS_PASSAGE; }
    public void receiveGraceRights(int nation) { politicalStatus[nation - 1] = HAS_GRACE; }

    public boolean isNeutral(int nation) { return nation == 0 || politicalStatus[nation - 1] == NEUTRAL;}
    public boolean isAllied(int nation) { return nation == 0 || politicalStatus[nation - 1] == ALLIED; }
    public boolean isAtWarWith(int nation) { return nation == 0 || politicalStatus[nation - 1] == WAR; }
    public boolean hasRightOfPassage(int nation) { return nation == 0 || politicalStatus[nation - 1] == HAS_PASSAGE; }
    public boolean hasGraceRights(int nation) { return nation == 0 || politicalStatus[nation - 1] == HAS_GRACE; }

    public int getNation() { return nation; }
    public int getPaps() { return PAPs; }
    public int getProductionPoints() { return productionPoints; }
    public User getControllingUser() { return controllingUser; }
    public boolean isPlayerNation() { return playerNation; }

    public ArrayList<MilitaryUnit> getMilitary() { return military; }
    public ArrayList<LandRegion> getTerritory() { return territory; }

    public ArrayList<LandRegion> getHomelands() {
        switch (getNation()) {
            case Nation.FRANCE: return map.getFrenchHomelands();
            case Nation.GREAT_BRITAIN: return map.getBritishHomelands();
            case Nation.PRUSSIA: return map.getPrussianHomelands();
            case Nation.RUSSIA: return map.getRussianHomelands();
            case Nation.OTTOMANS: return map.getOttomanHomelands();
            case Nation.AUSTRIA_HUNGRY: return map.getAustrianHomelands();
            case Nation.SPAIN: return map.getSpanishHomelands();
        }
        GameLogger.log("NationInstance.getHomelands: 'nation' does not match one of the seven nations");
        return null;
    }

    public ArrayList<Region> getHomelandPorts() {
        ArrayList<Region> ports = new ArrayList<Region>();
        ArrayList<LandRegion> homeland = getHomelands();

        for (Region p : map.getPorts())
            if( homeland.contains( ((Port)p).getPortRegion() ) )
                ports.add(p);

        return ports;
    }

    public ArrayList<NavalSquadron> getNavy() {
        ArrayList<NavalSquadron> navy = new ArrayList<NavalSquadron>();

        for (MilitaryUnit u : military) {
            if (u instanceof NavalSquadron)
                navy.add((NavalSquadron)u);
//            if (u instanceof Admiral)
//                navy.add((NavalSquadron)u);
        }
        return navy;
    }

    public ArrayList<MilitaryUnit> getArmy() {
        ArrayList<MilitaryUnit> army = new ArrayList<MilitaryUnit>();

        for (MilitaryUnit u : military) {
            if (u instanceof General)
                army.add(u);
            else if (u instanceof Infantry)
                army.add(u);
            else if (u instanceof EliteInfantry)
                army.add(u);
            else if (u instanceof Cavalry)
                army.add(u);
            else if (u instanceof HeavyCavalry)
                army.add(u);
            else if (u instanceof IrregularCavalry)
                army.add(u);
            else if (u instanceof Artillery)
                army.add(u);
            else if (u instanceof HorseArtillery)
                army.add(u);
            else if (u instanceof Militia)
                army.add(u);
        }
        return army;
    }

    public void setPaps(int paps) { this.PAPs = paps; }
    public void addPaps(int paps) { this.PAPs += paps; }
    public void minusPaps(int paps) { this.PAPs -= paps; }
    public void setProductionPoints(int points) { productionPoints = points; }
    public void addProductionPoints(int points) { productionPoints += points; }
    public void minusProductionPoints(int points) { productionPoints -= points; }
    public void setControllingUser(User user) { controllingUser = user; }
    public void setPlayerNation(boolean isPlayerNation) { this.playerNation = isPlayerNation; }

    private int nation;
    private int PAPs;
    private MapInstance map;
    private int scenario;
    private int productionPoints;
    private User controllingUser;
    private boolean playerNation;
    private ArrayList<MilitaryUnit> military;
    private ArrayList<LandRegion> territory;
    private int[] politicalStatus;
    private boolean isCapitalCaptured;
    private boolean hasCapitalBeenCaptured;
    private boolean isCapitalAnnexed;

    private final static int NEUTRAL        = 0;
    private final static int ALLIED         = 1;
    private final static int WAR            = 2;
    private final static int PASSAGE_RIGHTS = 3;
    private final static int GRACE_RIGHTS   = 4;
    private final static int HAS_PASSAGE    = 5;
    private final static int HAS_GRACE      = 6;
    private final static int THIS_NATION    = 7;
}